package com.gitee.feizns.dynamic.stream;

import com.gitee.feizns.dynamic.Lists;

import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <b>java8 流操作工具类</b>
 *
 * @see Stream
 * @author feizns
 * @since 2019/6/9 0009
 */
public abstract class Streams {

    /**
     * <b>将字符串转换为字节流</b>
     * @param string 字符串
     * @return 包含str中所有字符的流
     */
    public static Stream<Character> of(String string) {
        return string != null ? string.chars().mapToObj(ch -> (char) ch) : Stream.empty();
    }

    /**
     * 将数组列表转换为流
     * @param arrays 数组
     * @return 包含原collection中所有元素的流
     */
    @SafeVarargs
    public static <T> Stream<T> of(T[]... arrays) {
        return Lists.of(arrays).stream();
    }

    /**
     * 将集合转换为流
     * @param iterators 迭代器
     * @return 包含原collection中所有元素的流
     */
    @SafeVarargs
    public static <T> Stream<T> of(Iterator<T>... iterators) {
        return Lists.of(iterators).stream();
    }

    /**
     * 将一个可迭代的对象转换为流
     * @param iterables 可迭代对象
     * @return 包含原collection中所有元素的流
     */
    @SafeVarargs
    public static <T> Stream<T> of(Iterable<T>... iterables) {
        return Lists.of(iterables).stream();
    }

    /**
     * <b>创建一个拥有指定数量的流构建器的流</b>
     * @see Stream.Builder
     * @param size 流大小
     * @param <T> 流构建类型
     * @return 返回一个装有size个流构建器的流
     */
    public static <T> Stream<Stream.Builder<T>> builders(int size) {
        Stream.Builder<Stream.Builder<T>> builder = Stream.builder();
        for (int i = 0; i < size; i++) {
            builder.add(Stream.builder());
        }
        return builder.build();
    }

    /**
     * <b>将参数stream复制size份</b>
     * <p>
     *     java8中流被设计成仅能使用一次，用于需要重新利用的同一个流时。
     * </p>
     * @param stream 需要复制的流
     * @param size 需要复制多少份
     * @param <T> stream中数据的类型
     * @return 返回一个拥有size份流的流对象
     */
    public static <T> Stream<Stream<T>> clone(Stream<T> stream, int size) {
        Stream<Stream.Builder<T>> streamBuilders = builders(size);
        List<T> streamList = stream.collect(Collectors.toList());
        return streamBuilders.map(item -> {
            streamList.forEach(item::add);
            return item.build();
        });
    }

}
